<?php
/**
 * File Name...: helpers\date.php
 * Framework...: Blackbird Framework
 * Author......: KnKill, 2010 (c) KnKill Corporation
 */



/**
 * @package Blackbird Framework
 * @subpackage Helpers
 * @since 0.2
 */
class DateHelpers
{


/**
 * @static
 * @access public
 * @since 0.2
 * @param integer $month
 * @param integer $year
 * @return integer
 */
static public function days_in_month($month = 0, $year = 0) {
    // Если месяц не указан - используем текущий месяц
    if ($month === 0) {
        $month = date('m');
    }
    
    // Проверяем номер месяца на правильность
    if (intval($month) < 1 || intval($month) > 12) {
        return 0;
    }
    
    // Если год не в формате YYYY, где Y - число, тогда используем текущий год
    if (! is_numeric($year) || strlen($year) != 4) {
        $year = date('Y');
    }
    
    // Если выбранный месяц является февралём - проверяем, высокосный ли год,
    // и если да - вернуть 29 дней.
    if ($month == 2 && self::year_is_leap($year)) {
        return 29;
    }
    
    // Строим маасив с количеством дней в каждом месяце
    $days_in_month= array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    // Возвращаем результат
    return $days_in_month[$month - 1];
}


/**
 * @static
 * @access public
 * @since 0.2
 * @param integer $year
 * @return bool
*/
static public function year_is_leap($year = 0) {
    // Если год не указан, используем текущий год
    if ($year === 0) {
        $year = date('Y');
    }
    
    // Все вискосные года могут делится на 4
    if (($year % 4) != 0) {
        return false;
    }

    // Все вискоксные года могут делится на 400
    if ($year % 400 == 0) {
        return true;
    // Бла-бла-бла
    } else if (($year > 1582) && ($year % 100 == 0)) {
        return false;
    }
    // Если год високосный - возвращаем True
    return true;
}


/**
 * @static
 * @access public
 * @since 0.2
 * @param integer $day
 * @param integer $month
 * @param integer $year
 * @return integer
*/
static public function day_of_week($day = 0, $month = 0, $year = 0) {
    // Если год не указан - используем текущий год
    if ($year === 0) {
        $year = date('Y');
    }
    
    // Если месяц не указан - используем текущий месяц
    if ($month === 0) {
        $month = date('m');
    }
    
    // Если день не указан - используем текущий день
    if ($day === 0) {
        $day = date('d');
    }
    
    // Если год больше чем 1901 и меньше чем 2038, можно возвратить день недели
    // с помощью функций date и mktime
    if (($year > 1901) && ($year < 2038)) {
        return intval(date('w', mktime(0, 0, 0, $month, $day, $year)));
    }

    // В случае, если год не входит в эти рамки, необходимо произвести коррекцию по
    // григорианскому каленарю.
    $correction = 0;
    // Немного чёрной магии
    if (($year < 1582) || (($year == 1582) && (($month < 10) || (($month == 10) && ($day < 15))))) {
        // Мосле всей этой магии мы получаем 3. Так-то
        $correction = 3;
    }

    if ($month > 2) {
        $month -= 2;
    } else {
        $month += 10;
        $year--;
    }
    
    // MOOOOOOOOAR MATH!
    $day  = floor((13 * $month - 1) / 5) + $day + ($year % 100) + floor(($year % 100) / 4);
    // MOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOAR MATH!!!
    $day += floor(($year / 100) / 4) - 2 * floor($year / 100) + 77 + $correction;

    return intval($day - 7 * floor($day / 7));
}


/**
 * @static
 * @access public
 * @since 0.2
 * @param integer $day
 * @param integer $month
 * @param integer $year
 * @return integer
*/
static public function week_of_year($day = 0, $month = 0, $year = 0) {
    // Если год не указан - используем текущий год
    if ($year === 0) {
        $year = date('Y');
    }
    
    // Если месяц не указан - используем текущий месяц
    if ($month === 0) {
        $month = date('m');
    }
    
    // Если день не указан - используем текущий день
    if ($day === 0) {
        $day = date('d');
    }
    
    // Получаем "Unix timestamp" основываясь на указанных параметрах
    $date = mktime(0, 0, 0, $month, $day, $year);
    
    // Если первый день года понедельник, первый день это первое января
    if (date('D', mktime(0, 0, 0, 1, 1, $year)) == 'Mon') {
        $firstDay = mktime(0, 0, 0, 1, 1, $year); 
    } else { 
        if (date('z', mktime(0, 0, 0, $month, $day, $year)) >= '361') {
            // Вот почему у меня постоянно появляется желание вставить
            // какой-то тупой комментарий в код?
            $firstDay = strtotime('last Monday', mktime(0, 0, 0, 1, 1, $year + 1)); 
        } else { 
            $firstDay = strtotime('last Monday', mktime(0, 0, 0, 1, 1, $year)); 
        } 
    }
    
    // Вычисляем, сколько дней прошло начиная с первого дня
    $passed = ($date - $firstDay) / 60 / 60 / 24; 
    if (date('D', mktime(0, 0, 0, $month, $day, $year)) == 'Sun') {
        $sunday = mktime(0, 0, 0, $month, $day, $year);
    } else {
        $sunday = strtotime('next Sunday', mktime(0, 0, 0, $month, $day, $year));
    } 
    $left = ($sunday - $date) /60 / 60 / 24;
    
    // Возвращаем результат
    return ($passed + $left + 1) / 7; 
}


// End Of Helper "Date"
}